home *** CD-ROM | disk | FTP | other *** search
- /* v f s c a n f
- *
- * Formatted read from a stream. This function uses varargs to
- * obtain the argument list. It is the basis of the family of
- * scanf functions in this stdio implementation.
- *
- * The user is referred to the manual page for a full
- * description of the formats available.
- *
- * The function returns EOF on end of input, and a short count
- * for missing or illegal data items.
- *
- * Patchlevel 1.1
- *
- * Edit History:
- * 05-Sep-1989 Include limits.h if TOLOWER undefined so removing
- * need to define MINIX when compiling.
- */
-
- #include <ctype.h>
- #include "stdiolib.h"
- #include "bitset.h"
-
- #if defined(BSD)
- # include <values.h>
- # define TOLOWER(c) (isupper((c)) ? tolower((c)) : (c))
- # define CHARSET (1 << (BITSPERBYTE))
- #endif
-
- #if !defined(TOLOWER)
- # include <limits.h>
- # define TOLOWER(c) (tolower((c)))
- # define CHARSET (1 << (CHAR_BIT))
- extern int tolower P((int));
- #endif
-
- #define WHITESPACE(c) ((c)==' '||(c)=='\t'||(c)=='\n')
- #define NEXTCH() (ch = getc(fp))
- #define ENDFIELD() \
- if (fieldok) { \
- if (! noassign) items++; \
- } \
- else \
- goto Putback;
-
- int vfscanf(fp, fmt, args)
-
- FILE *fp; /* stream */
- char *fmt; /* format */
- va_list args; /* arguments */
-
- {
- bitstring(cset, CHARSET); /* set for %[] */
- int items; /* number of items done */
- int ch; /* next character */
- int lch; /* lowercase version of character */
- int i; /* general index */
- char *p; /* string pointer */
- char skipspace; /* force white space skip */
- char noassign; /* do not do assignment */
- char longflag; /* pointer is long */
- char shortflag; /* pointer is short */
- char fieldok; /* this field parsed ok */
- char invertedset; /* inverted set */
- char sign; /* conversion is signed */
- char negative; /* number is negative */
- int fieldwidth; /* width of field */
- unsigned radix; /* radix for conversion */
- unsigned lastdigit; /* last digit (0-9) in radix */
- long longv; /* long value for conversion */
-
- /* Prime the look ahead character */
- if (NEXTCH() == EOF)
- return EOF;
-
- for (items = 0; ; fmt++) {
-
- /* Skip whitespace in format */
- for (skipspace = 0; WHITESPACE(*fmt); fmt++)
- skipspace = 1;
-
- /* Check for end of format or end of input */
- if (*fmt == 0 || ch == EOF)
- goto Putback;
-
- /* Check for verbatim character */
- if (*fmt != '%') {
- while (WHITESPACE(ch))
- NEXTCH();
-
- if (ch != *fmt)
- goto Putback;
-
- NEXTCH();
- continue;
- }
-
- /* Format precursor seen --- see if assignment required */
- if ((noassign = *++fmt == '*') != 0)
- fmt++;
-
- /* Check for width specification */
- fieldwidth = -1;
- if (*fmt >= '0' && *fmt <= '9') {
- for (fieldwidth = 0; *fmt >= '0' && *fmt <= '9'; )
- fieldwidth = fieldwidth * 10 + *fmt++ - '0';
- }
-
- /* Check for long or short pointers */
- if ((longflag = *fmt == 'l') != 0 || (shortflag = *fmt == 'h') != 0)
- fmt++;
-
- /* Skip whitespace in the input stream */
- if (skipspace || (*fmt != 'c' && *fmt != '[')) {
- while (WHITESPACE(ch))
- NEXTCH();
- }
-
- /* Assume that field is not parsed */
- fieldok = 0;
-
- switch (*fmt) {
-
- case 'O': longflag = 1;
- case 'o': radix = 8; lastdigit = '7'; sign = 0; goto oxud;
- case 'U': longflag = 1;
- case 'u': radix = 10; lastdigit = '9'; sign = 0; goto oxud;
- case 'D': longflag = 1;
- case 'd': radix = 10; lastdigit = '9'; sign = 1; goto oxud;
- case 'X': longflag = 1;
- case 'x': radix = 16; lastdigit = '9'; sign = 0;
-
- oxud:
- longv = 0;
- negative = 0;
-
- /* Look for sign if number is signed */
- if (fieldwidth != 0 && sign && ch == '+')
- NEXTCH();
- else if (fieldwidth != 0 && sign && ch == '-') {
- negative = 1;
- NEXTCH();
- }
-
- /* Scan and convert */
- while (fieldwidth < 0 || fieldwidth--) {
- if (ch >= '0' && ch <= lastdigit)
- ch -= '0';
- else {
- lch = TOLOWER(ch);
- if (lch >= 'a' && (lch += 10 - 'a') < radix)
- ch = lch;
- else
- break;
- }
- longv = longv * radix + ch;
- NEXTCH();
- fieldok = 1;
- }
-
- /* Complete the conversion */
- if (! noassign) {
- if (negative)
- longv = -longv;
- if (longflag)
- if (sign) *va_arg(args, long *) = longv;
- else *va_arg(args, unsigned long *) = longv;
- else if (shortflag)
- if (sign) *va_arg(args, short *) = (short) longv;
- else *va_arg(args, unsigned short *) = (unsigned short) longv;
- else
- if (sign) *va_arg(args, int *) = (int) longv;
- else *va_arg(args, unsigned int *) = (unsigned int) longv;
- }
- ENDFIELD();
- break;
-
- case 'c':
- if (fieldwidth == -1)
- fieldwidth = 1;
-
- /* Initialise the string pointer */
- if (! noassign)
- p = va_arg(args, char *);
-
- while (fieldwidth-- && ch >= 0) {
- *p++ = ch;
- NEXTCH();
- fieldok = 1;
- }
- ENDFIELD();
- break;
-
- case 's':
-
- /* Initialise the string pointer */
- if (! noassign)
- p = va_arg(args, char *);
-
- while (fieldwidth < 0 || fieldwidth--) {
- if (ch <= 0 || WHITESPACE(ch))
- break;
- *p++ = ch;
- NEXTCH();
- fieldok = 1;
- }
-
- /* Terminate the string with a null */
- if (! noassign)
- *p++ = 0;
- ENDFIELD();
- break;
-
- case '[':
-
- /* Clear the bit set */
- bitempty(cset, CHARSET);
-
- /* Check for inverted set */
- if ((invertedset = *++fmt == '^') != 0)
- fmt++;
-
- /* Check for right bracket in set */
- if (*fmt == ']')
- bitset(cset, *fmt++);
-
- /* Scan search set, setting bits */
- while (*fmt != 0 && *fmt != ']') {
- if (fmt[1] != '-' || fmt[2] == ']' || fmt[2] == 0 || fmt[0] > fmt[2])
- bitset(cset, *fmt++);
- else {
- for (i = fmt[0]; i <= fmt[2]; i++)
- bitset(cset, i);
- fmt += 3;
- }
- }
-
- /* Check for unsatisfactory set construction */
- if (*fmt != ']')
- goto Putback;
-
- /* Initialise string pointer */
- if (! noassign)
- p = va_arg(args, char *);
-
- /* Scan input for satisfactory characters */
- while (fieldwidth < 0 || fieldwidth--) {
- if (WHITESPACE(ch) || ch <= 0 || ! (bittest(cset, ch) ^ invertedset))
- break;
- *p++ = ch;
- NEXTCH();
- fieldok = 1;
- }
-
- /* Terminate string with null */
- if (! noassign)
- *p++ = 0;
- ENDFIELD();
- break;
- }
- }
-
- /* Restore the look ahead character */
- Putback:
- if (ch != EOF)
- (void) ungetc(ch, fp);
- return items;
- }
-